home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume25 / zip / part03 < prev    next >
Encoding:
Text File  |  1992-03-01  |  61.3 KB  |  1,879 lines

  1. Newsgroups: comp.sources.unix
  2. From: madler@cco.caltech.edu (Mark Adler)
  3. Subject: v25i144: zip - file compression/archive tool, Part03/07
  4. Sender: unix-sources-moderator@pa.dec.com
  5. Approved: vixie@pa.dec.com
  6.  
  7. Submitted-By: madler@cco.caltech.edu (Mark Adler)
  8. Posting-Number: Volume 25, Issue 144
  9. Archive-Name: zip/part03
  10.  
  11. #! /bin/sh
  12. # This is a shell archive.  Remove anything before this line, then unpack
  13. # it by saving it into a file and typing "sh file".  To overwrite existing
  14. # files, type "sh file -c".  You can also feed this as standard input via
  15. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  16. # will see the following message at the end:
  17. #        "End of archive 3 (of 7)."
  18. # Contents:  zip.1 zipfile.c zipsplit.c
  19. # Wrapped by vixie@cognition.pa.dec.com on Sun Mar  1 18:57:38 1992
  20. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  21. if test -f 'zip.1' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'zip.1'\"
  23. else
  24. echo shar: Extracting \"'zip.1'\" \(21611 characters\)
  25. sed "s/^X//" >'zip.1' <<'END_OF_FILE'
  26. X.\" Copyright (C) 1990,1991 Mark Adler, Richard B. Wales, and Jean-loup Gailly.
  27. X.\" Permission is granted to any individual or institution to use, copy, or
  28. X.\" redistribute this software so long as all of the original files are included
  29. X.\" unmodified, that it is not sold for profit, and that this copyright notice
  30. X.\" is retained.
  31. X.\"
  32. X.\" zip.1 by Mark Adler.
  33. X.\"
  34. X.TH ZIP 1
  35. X.SH NAME
  36. zip \- package and compress (archive) files
  37. X.SH SYNOPSIS
  38. X.B zip
  39. X[
  40. X.B \-cdefghijklmnoqrsuwyz
  41. X] [
  42. X.B \-b
  43. path ] [
  44. X.B \-t
  45. mmddyy ] zipfile list [
  46. X.B \-x
  47. list ]
  48. X.br
  49. X.SH DESCRIPTION
  50. X.I Zip
  51. is a compression and file packaging utility for Unix, MSDOS, OS/2, and VMS.
  52. It is
  53. analogous to a combination of tar and compress and is compatible with PKZIP
  54. X(Phil Katz ZIP) for MSDOS systems.
  55. X.PP
  56. There is a companion to
  57. X.I Zip
  58. called
  59. X.I UnZip
  60. X(of course) which you should be able
  61. to find the same place you got
  62. X.I Zip.  Zip
  63. and
  64. X.I UnZip
  65. can work with files
  66. produced by PKZIP under MSDOS, and PKZIP and PKUNZIP can work with files
  67. produced by
  68. X.I Zip.
  69. X.PP
  70. X.I Zip
  71. puts one or more compressed files into a single "zip file" along with
  72. information about the files, including the name, path if requested, date
  73. and time last modified, protection, and check information to verify the
  74. fidelity of each entry.
  75. X.I Zip
  76. can pack an entire directory structure in a
  77. zip file with a single command.  Compression ratios of 2:1 to 3:1 are
  78. common for text files.
  79. X.I Zip
  80. has two compression methods, implosion and
  81. shrinking, and automatically chooses the better of the two for each file
  82. to be compressed.
  83. X.PP
  84. X.I Zip
  85. is useful for packaging a set of files to send to someone or for
  86. distribution; for archiving or backing up files; and for saving disk space by temporarily
  87. compressing unused files or directories.
  88. X.SH "HOW TO INSTALL ZIP"
  89. X.I Zip
  90. is distributed as C source code that can be compiled on a wide range of
  91. Unix machines, VAXes running VMS, and MSDOS machines using
  92. Microsoft or Borland C++, and OS/2 machines using Microsoft C.
  93. You will
  94. need Unzip (under Unix, MSDOS, or VMS) or PKUNZIP (under MSDOS) to unpack the
  95. distribution file, zip10.zip.
  96. X.PP
  97. XFirst, unpack the source as follows, assuming that you
  98. have zip10.zip in the current directory:
  99. X.PP
  100. X.ti+5n
  101. mkdir zipsrc
  102. X.ti+5n
  103. cd zipsrc
  104. X.ti+5n
  105. unzip ../zip10
  106. X.PP
  107. This extracts all source files and documentation in the directory called
  108. X"zipsrc". You then do:
  109. X.PP
  110. X.ti+5n
  111. make system
  112. X.PP
  113. where "system" is one of: bsd, bsdold, sysv, next, next10, sun, hpux, dnix,
  114. cray, 3b1, zilog, aux, convex, aix, or minix.  If you are using a NeXT
  115. running version
  116. X2.0 or greater, then make next.  If you are using 1.0, then make
  117. next10.  If you
  118. are using Sun OS 4.x, then make sun.  If you are using HPUX, then make hpux.
  119. The other special systems are DNIX 5.2 or 5.3, Cray Unicos,
  120. AT&T 3B1 (also known as Unix PC or PC 7300), Zilog Zeus, A/UX, Convex, AIX,
  121. and MINIX.
  122. Otherwise, if you are using BSD Unix, try bsd.  If the linker cannot find
  123. X_memset or _memcpy, try bsdold.  If you are using System V Unix or SCO Unix,
  124. try sysv.  Also use sysv on a Silicon Graphics (SGI) machine.
  125. You can also cross-compile
  126. X.I Zip
  127. for MSDOS under SCO 386 Unix using "make scodos".
  128. X.PP
  129. If none of these compiles, links, and functions properly on your Unix system,
  130. see the section BUGS below for how to get help.
  131. X.PP
  132. If the appropriate system was selected, then the executable "zip" will be
  133. created.  You can move the executable "zip" to an appropriate directory
  134. in the search path using a command like:
  135. X.PP
  136. X.ti+5n
  137. mv zip ~/bin
  138. X.PP
  139. or
  140. X.PP
  141. X.ti+5n
  142. mv zip /usr/local/bin
  143. X.PP
  144. You can use the command "set" to see the current search path.  If you are
  145. using the C-Shell (csh), enter the command:
  146. X.PP
  147. X.ti+5n
  148. rehash
  149. X.PP
  150. so csh can find the new command in the path.  You are now ready to use
  151. X.I Zip.
  152. X.PP
  153. You can also move the manual page (the raw form of what you're reading)
  154. to where the Unix man command can find it (assuming you have the necessary
  155. privileges):
  156. X.PP
  157. X.ti+5n
  158. mv zip.1 /usr/man/man1
  159. X.PP
  160. You can get rid of the now unnecessary source and object files with:
  161. X.PP
  162. X.ti+5n
  163. cd ..
  164. X.ti+5n
  165. rm -r zipsrc
  166. X.PP
  167. This will remove the directory zip and its contents created by unzip.
  168. You should keep the zip10.zip file around though, in case you
  169. need to build it again or want to give it to a colleague.
  170. X.PP
  171. The steps for installation under MSDOS, OS/2, and VMS are similar to the above:
  172. first unzip the distribution files into their own directory.  Then under
  173. MSDOS do one of:
  174. X.PP
  175. X.ti+5n
  176. make makefile.msc
  177. X.ti+5n
  178. make -fmakefile.bor
  179. X.PP
  180. for Microsoft or Borland C++, respectively.  Under OS/2:
  181. X.PP
  182. X.ti+5n
  183. nmake -f makefile.os2
  184. X.PP
  185. for Microsoft C 6.00.  Under VAX VMS:
  186. X.PP
  187. X.ti+5n
  188. X@makevms
  189. X.PP
  190. The installation process will also compile and link several
  191. other utilities.  They are zipcloak for encrypting and decrypting zip files,
  192. zipnote for editing zip file comments, zipsplit for splitting a zip file
  193. into several zip files, and ship for sending zip files or any other binary
  194. file via electronic mail.  For command help on any of the zip* utilities,
  195. simply enter the name with no arguments.  For help with ship, enter "ship -h".
  196. X.SH "HOW TO USE ZIP"
  197. The simplest use of
  198. X.I Zip
  199. is as follows:
  200. X.PP
  201. X.ti+5n
  202. zip stuff *
  203. X.PP
  204. This will create the file "stuff.zip" (assuming it does not exist) and put
  205. all the files in the current directory in stuff.zip in a compressed form.
  206. The .zip suffix is added automatically, unless that file name given contains
  207. a dot already.  This allows specifying suffixes other than ".zip".
  208. X.PP
  209. Because of the way the shell does filename substitution, files that start
  210. with a "." are not included.  To include those as well, you can:
  211. X.PP
  212. X.ti+5n
  213. zip stuff .* *
  214. X.PP
  215. XEven this will not include any subdirectories that are in the current
  216. directory.  To zip up an entire directory, the command:
  217. X.PP
  218. X.ti+5n
  219. zip -r foo foo
  220. X.PP
  221. will create the file "foo.zip" containing all the files and directories in
  222. the directory "foo" that is in the current directory.  The "r" option means
  223. recurse through the directory structure.  In this case, all the
  224. files and directories in foo are zipped, including the ones that start with
  225. a ".", since the recursion does not use the shell's file-name substitution.
  226. You should not use -r with the name ".*", since that matches ".." which will
  227. attempt to zip up the parent directory--probably not what was intended.
  228. X.PP
  229. You may want to make a zip file that contains the files in foo, but not record
  230. the directory name, foo.  You can use the -j (junk path) option to leave off
  231. the path:
  232. X.PP
  233. X.ti+5n
  234. zip -j foo foo/*
  235. X.PP
  236. The -y option (only under Unix) will store symbolic links as such in the
  237. zip file, instead of compressing and storing the file referred to in the link.
  238. X.PP
  239. You might be zipping to save disk space, in which case you could:
  240. X.PP
  241. X.ti+5n
  242. zip -rm foo foo
  243. X.PP
  244. where the "m" option means "move".  This will delete foo and its contents
  245. after making foo.zip.  No deletions will be done until the zip has completed
  246. with no errors.  This option is obviously more dangerous and should be
  247. used with care.
  248. X.PP
  249. If the zip file already exists, these commands will replace existing or add
  250. new entries to the zip file.  For example, if you were really short on disk
  251. space, you might not have enough room simultaneously to hold the directory
  252. foo and the compressed foo.zip.  In this case, you could do it in steps.  If
  253. foo contained the subdirectories tom, dick, and harry, then you could:
  254. X.PP
  255. X.ti+5n
  256. zip -rm foo foo/tom
  257. X.ti+5n
  258. zip -rm foo foo/dick
  259. X.ti+5n
  260. zip -rm foo foo/harry
  261. X.PP
  262. where the first command would create foo.zip, and the next two would add to
  263. it.  At the completion of each zip command, the directory just zipped would
  264. be deleted, making room in which the next
  265. X.I Zip
  266. command could work.
  267. X.SH "MODIFYING EXISTING ZIP FILES"
  268. When given the name of an existing zip file with the above commands,
  269. X.I Zip
  270. will replace identically named entries in the
  271. X.I Zip
  272. file or add entries for
  273. new names.  For example, if foo.zip exists and contains foo/file1 and
  274. foo/file2, and the directory foo contains the files foo/file1 and foo/file3,
  275. then:
  276. X.PP
  277. X.ti+5n
  278. zip -r foo foo
  279. X.PP
  280. will replace foo/file1 in foo.zip and add foo/file3 to foo.zip.  After
  281. this, foo.zip contains foo/file1, foo/file2, and foo/file3, with foo/file2
  282. unchanged from before.
  283. X.PP
  284. When changing an existing zip file,
  285. X.I Zip
  286. will write a temporary file with
  287. the new contents, and only replace the old one when the zip has completed
  288. with no errors.  Also, the two methods, shrink and implode, create
  289. temporary files that are deleted after each file is zipped.  You can use
  290. the -b option to specify a different path (usually a different device) to
  291. put the temporary files in.  For example:
  292. X.PP
  293. X.ti+5n
  294. zip -b /tmp stuff *
  295. X.PP
  296. will put the temporary zip file and the temporary compression files in the
  297. directory "/tmp", copying over stuff.zip in the current directory when
  298. done.
  299. X.PP
  300. If you are only adding entries to a zip file, not replacing, and the
  301. X-g option is given, then
  302. X.I Zip
  303. grows (appends to) the file instead of copying it.  The danger of this is that
  304. if the operation fails, the original zip file is corrupted and lost.
  305. X.PP
  306. There are two other ways to change or add entries in a zip file that are
  307. restrictions of simple addition or replacement.  The first is -u (update)
  308. which will add new entries to the zip file as before but will replace
  309. existing entries only if the modified date of the file is more recent than
  310. the date recorded for that name in the zip file.  For example:
  311. X.PP
  312. X.ti+5n
  313. zip -u stuff *
  314. X.PP
  315. will add any new files in the current directory, and update any changed files
  316. in the zip file stuff.zip.  Note that
  317. X.I Zip
  318. will not try to pack stuff.zip into
  319. itself when you do this. 
  320. X.I Zip
  321. will always exclude the zip file from the files on which to be operated.
  322. X.PP
  323. The second restriction is -f (freshen) which, like update, will only replace
  324. entries with newer files; unlike update, will not add files that are not
  325. already in the zip file.  For this option, you may want to simply freshen all
  326. of the files that are in the specified zip file.  To do this you would simply:
  327. X.PP
  328. X.ti+5n
  329. zip -f foo
  330. X.PP
  331. Note that the -f option with no arguments freshens all the entries in the
  332. zip file.  The same is true of -u, and hence "zip -u foo" and "zip -f foo"
  333. both do the same thing.
  334. X.PP
  335. This command should
  336. be run from the same directory from which the original zip command was run,
  337. since paths stored in zip files are always relative.
  338. X.PP
  339. Another restriction that can be used with adding, updating, or freshening is
  340. X-t (time), which will not operate on files modified earlier than the specified
  341. date.  For example:
  342. X.PP
  343. X.ti+5n
  344. zip -rt 120791 infamy foo
  345. X.PP
  346. will add all the files in foo and its subdirectories that were last modified
  347. on December 7, 1991, or later to the zip file infamy.zip.
  348. X.PP
  349. Also, files can be explicitly excluded using the -x option:
  350. X.PP
  351. X.ti+5n
  352. zip -r foo foo -x \\*.o
  353. X.PP
  354. which will zip up the contents of foo into foo.zip but exclude all the
  355. files that end in ".o".  Here the backslash causes
  356. X.I Zip
  357. to match file names
  358. that were found when foo was searched.
  359. X.PP
  360. The last operation is -d (delete) which will remove entries from a zip file.
  361. An example might be:
  362. X.PP
  363. X.ti+5n
  364. zip -d foo foo/tom/junk foo/harry/\\* \\*.o
  365. X.PP
  366. which will remove the entry foo/tom/junk, all of the files that start with
  367. X"foo/harry/", and all of the files that end with ".o" (in any path).  Note
  368. that once again, the shell expansion has been inhibited with backslashes, so
  369. that
  370. X.I Zip
  371. can see the asterisks.  
  372. X.I Zip
  373. can then match on the contents of the zip
  374. file instead of the contents of the current directory.
  375. X.PP
  376. Under MSDOS, -d is case sensitive when it matches names in the zip file.
  377. This allows deleting names that were zipped on other systems, but requires
  378. that the names be entered in upper case if they were zipped on an MSDOS
  379. system, so that the names can be found in the zip file and deleted.
  380. X.SH "MORE OPTIONS"
  381. As mentioned before,
  382. X.I Zip
  383. will use the best of two methods: shrink or implode.
  384. Usually implode is better, but sometimes shrink is better, especially for
  385. smaller files.  Sometimes neither method produces a packed version smaller
  386. than the original file, in which case it is stored in the zip file with no
  387. compression (called the "store" method).
  388. X.PP
  389. The option -s (shrink) will force
  390. X.I Zip
  391. always to use shrink or store, and the
  392. X-i (implode) option forces
  393. X.I Zip
  394. to use implode or store.  Shrinking is faster
  395. than imploding, and so -s might be used when speed is more important than
  396. optimal compression.  Implode only (-i) might be used when the unzipper 
  397. for which the
  398. zip file is destined can only handle implosion.  An example of this is
  399. the PKSFXjr program that comes with PKZIP.  Also, -i is slightly faster
  400. than imploding and shrinking at the same time.  For example:
  401. X.PP
  402. X.ti+5n
  403. zip -rs foo foo
  404. X.PP
  405. will zip up the directory foo into foo.zip using only shrink or store.
  406. The speed of implosion can also be controlled with options -0 (fastest
  407. method but less compression) to -9 (best compression but slower). The
  408. default value is -5. For example:
  409. X.PP
  410. X.ti+5n
  411. zip -r0 foo foo
  412. X.PP
  413. In nearly all cases, a file that is already compressed cannot be compressed
  414. further by
  415. X.I Zip,
  416. or if it can, the effect is minimal.  The -n option prevents
  417. X.I Zip
  418. from trying to compress files that have the suffixes: .Z, .zip, .zoo,
  419. or .arc.  Such files are simply stored (0% compression) in the output zip file,
  420. so that
  421. X.I Zip
  422. doesn't waste its time trying to compress them.
  423. If the environment variable NOZIP is set, then the suffixes listed
  424. there are used instead of the default list.  The suffixes are separated by
  425. either colons or semicolons.  For example, in Unix csh:
  426. X.PP
  427. X.ti+5n
  428. setenv NOZIP .Z:.zip:.tiff:.gif:.snd
  429. X.ti+5n
  430. zip -rn foo foo
  431. X.PP
  432. will put everything in foo into foo.zip, but will store any files that end
  433. in .Z, .zip, .tiff, .gif, or .snd without trying to compress them.  (Image
  434. and sound files often have their own specialized compression methods.)  If
  435. the environment variable NOZIP exists but is empty or contains just a colon
  436. or semicolon, then zip -n will store all the entries and do no compression.
  437. X.PP
  438. Under Unix and under OS/2 (if files from a HPFS are stored),
  439. X.I Zip
  440. will store the full path (relative to the current path) and name of the
  441. file (or just the name if -j is specified) in the zip file along with the
  442. Unix attributes, and it will mark
  443. the entry as made under Unix.  If the zip file is intended for PKUNZIP under
  444. MSDOS, then the -k (Katz) option should be used to attempt to convert the
  445. names and paths to conform to MSDOS, store only the MSDOS attribute (just
  446. the user write attribute from Unix), and mark the entry as made under MSDOS
  447. X(even though it wasn't).
  448. X.PP
  449. The -o (older) option will set the "last modified" time of the zip file to
  450. the latest "last modified" time of the entries in the zip file.  This can
  451. be used without any other operations, if desired.  For example:
  452. X.PP
  453. X.ti+5n
  454. zip -o foo
  455. X.PP
  456. will change the last modified time of foo.zip to the latest time of the
  457. entries in foo.zip.
  458. X.PP
  459. The -e and -c options operate on all files updated or added to the zip file.
  460. XEncryption (-e) will prompt for a password on the terminal and will
  461. not echo the password as it is typed (if stderr is not a TTY, Zip will exit
  462. with an error).  New zip entries will be encrypted using that password.  For
  463. added peace of mind, you can use -ee, which will prompt for the password
  464. twice, checking that the two are the same before using it.
  465. X.PP
  466. One-line comments can be added for each file with the -c option.  The zip
  467. file operations (adding or updating) will be done first, and you will then be
  468. prompted for a one-line comment for each file.  You can then enter the comment
  469. followed by return, or just return for no comment.
  470. X.PP
  471. The -z option will prompt you for a multi-line comment for the entire zip
  472. file.  This option can be used by itself, or in combination with other
  473. options.  The comment is ended by a line containing just a period, or an end
  474. of file condition (^D on Unix, ^Z on MSDOS, OS/2, and VAX/VMS).
  475. Since -z reads the
  476. lines from stdin, you can simply take the comment from a file:
  477. X.PP
  478. X.ti+5n
  479. zip -z foo < foowhat
  480. X.PP
  481. The -q (quiet) option eliminates the informational messages and comment prompts
  482. while
  483. X.I Zip
  484. is operating.  This might be used in shell scripts, for example, or if the
  485. zip operation is being performed as a background task ("zip -q foo *.c &").
  486. X.PP
  487. X.I Zip
  488. can take a list of file names to operate on from stdin using the - option.
  489. In Unix, this option can be used with the find command to extend greatly
  490. the functionality of
  491. X.I Zip.
  492. XFor example, to zip up all the C source files in the current directory and
  493. its subdirectories, you can:
  494. X.PP
  495. X.ti+5n
  496. find . -type f -name "*.[ch]" -print | zip source -
  497. X.PP
  498. Note that the pattern must be quoted to keep the shell from expanding it.
  499. X.PP
  500. Under VMS only, the -w option will append the version number of the files to
  501. the name and zip up multiple versions of files.  Without -w,
  502. X.I Zip
  503. will only use the most recent version of the specified file(s).
  504. X.PP
  505. If
  506. X.I Zip
  507. is run with no arguments or with the -h option, the license and the
  508. command-argument and option help is shown.  The -l option just shows the
  509. license.
  510. X.SH "ABOUT PATTERN MATCHING"
  511. X(Note: this section applies to Unix.  Watch this space for details on MSDOS
  512. and VMS operation.)
  513. X.PP
  514. The Unix shell (sh or csh) does filename substitution on command arguments.
  515. The special characters are ?, which matches any single character; * which
  516. matches any number of characters (including none); and [] which matches any
  517. character in the range inside the brackets (like [a\-f] or [0\-9]).  When
  518. these characters are encountered (and not escaped with a backslash or
  519. quotes), the
  520. shell will look for files relative to the current path that match the
  521. pattern, and replace the argument with a list of the names that matched.
  522. X.PP
  523. X.I Zip
  524. can do the same matching on names that are in the zip file being
  525. modified or, in the case of the -x (exclude) option, on the list of
  526. files to be operated on, by using backslashes or quotes
  527. to tell the shell not to do the name expansion.  In general, when
  528. X.I Zip
  529. encounters a name in the list
  530. of files to do, it first looks for the name in the file system.  If it
  531. finds it, it then adds it to the list of files to do.  If it does not
  532. find it, it will look for the name in the zip file being modified (if it
  533. exists), using the pattern matching characters above, if any.  For each
  534. match, it will add that name to the list of files to do.  After -x
  535. X(exclude), the names are removed from the to-do list instead of added.
  536. X.PP
  537. The pattern matching includes the path, and so patterns like \\*.o match
  538. names that end in ".o", no matter what the path prefix is.  Note that the
  539. backslash must precede every special character (i.e. ?*[]), or the entire
  540. argument must be enclosed in double quotes ("").
  541. X.PP
  542. In general, using backslash to make
  543. X.I Zip
  544. do the pattern matching is used
  545. with the -f (freshen) and -d (delete) options, and sometimes after the
  546. X-x (exclude) option when used with any operation (add, -u, -f, or -d).
  547. X.I Zip
  548. will never use pattern matching to search the file system.  If
  549. X.I Zip
  550. has recursed into a directory, all files (and all directories) in there
  551. are fair game.
  552. X.SH COPYRIGHT
  553. Copyright (C) 1990,1991 Mark Adler, Richard B. Wales, and Jean-loup Gailly.
  554. Permission is granted to any individual or institution to use, copy, or
  555. redistribute this software so long as all of the original files are included
  556. unmodified, that it is not sold for profit, and that this copyright notice
  557. is retained.
  558. X.SH ACKNOWLEDGEMENTS
  559. Thanks to R. P. Byrne for his Shrink.Pas program which inspired this project,
  560. and from which the shrink algorithm was stolen; to Phil Katz for making the zip
  561. file format, compression format, and .ZIP filename extension all public domain;
  562. to Keith Petersen for providing a mailing list and ftp site for the INFO-ZIP
  563. group to use; and most importantly, to the INFO-ZIP group itself (listed in
  564. the file infozip.who) without whose tireless testing and bug-fixing efforts
  565. a portable
  566. X.I Zip
  567. would not have been possible.  Finally we should thank (blame) the INFO-ZIP
  568. moderator, David Kirschbaum for getting us into this mess in the first place.
  569. X.SH "SEE ALSO"
  570. unzip(1), tar(1), compress(1)
  571. X.SH BUGS
  572. Versions of PKUNZIP before 1.1 have a bug that on rare occasions will prevent
  573. it from unzipping files produced by
  574. X.I Zip
  575. or PKZIP 1.1.  If you experience such problems, we recommend that you get
  576. PKUNZIP 1.1 or the portable
  577. X.I Unzip,
  578. neither of which have this problem.
  579. X.PP
  580. Under MSDOS, Zip will find hidden and system files, but not set the
  581. attributes appropriately in the zip file so that Unzip can restore them.
  582. This will be fixed in the next version.
  583. X.PP
  584. Under VMS, not all of the odd file formats are treated properly.  Only
  585. stream-LF format zip files are expected to work with Zip.  Others can be
  586. converted using Rahul Dhesi's BILF program.  The next version of Zip will
  587. handle some of the conversion internally.
  588. X.PP
  589. LIKE ANYTHING ELSE THAT'S FREE, ZIP AND ITS ASSOCIATED UTILITIES ARE
  590. PROVIDED AS IS AND COME WITH NO WARRANTY OF ANY KIND, EITHER EXPRESSED OR
  591. IMPLIED. IN NO EVENT WILL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DAMAGES
  592. RESULTING FROM THE USE OF THIS SOFTWARE.
  593. X.PP
  594. That having been said, please send any problems or comments via email to
  595. the Internet address
  596. zip\-bugs@cs.ucla.edu.  For bug reports, please include the
  597. version of Zip, the make options you used to compile it, the machine and
  598. operating system you are using, and as much additional information as
  599. possible.  Thank you for your support.
  600. END_OF_FILE
  601. if test 21611 -ne `wc -c <'zip.1'`; then
  602.     echo shar: \"'zip.1'\" unpacked with wrong size!
  603. fi
  604. # end of 'zip.1'
  605. fi
  606. if test -f 'zipfile.c' -a "${1}" != "-c" ; then 
  607.   echo shar: Will not clobber existing file \"'zipfile.c'\"
  608. else
  609. echo shar: Extracting \"'zipfile.c'\" \(20530 characters\)
  610. sed "s/^X//" >'zipfile.c' <<'END_OF_FILE'
  611. X/*
  612. X
  613. X Copyright (C) 1990,1991 Mark Adler, Richard B. Wales, and Jean-loup Gailly.
  614. X Permission is granted to any individual or institution to use, copy, or
  615. X redistribute this software so long as all of the original files are included
  616. X unmodified, that it is not sold for profit, and that this copyright notice
  617. X is retained.
  618. X
  619. X*/
  620. X
  621. X/*
  622. X *  zipfile.c by Mark Adler.
  623. X */
  624. X
  625. X#include "zip.h"
  626. X
  627. X
  628. X/* Macros for converting integers in little-endian to machine format */
  629. X#define SH(a) (((ush)(uch)(a)[0]) | (((ush)(uch)(a)[1]) << 8))
  630. X#define LG(a) ((ulg)SH(a) | ((ulg)SH((a)+2) << 16))
  631. X
  632. X/* Macros for writing machine integers to little-endian format */
  633. X#define PUTSH(a,f) {putc((char)(a),(f)); putc((char)((a) >> 8),(f));}
  634. X#define PUTLG(a,f) {PUTSH(a,f) PUTSH((a) >> 16,f)}
  635. X
  636. X
  637. X/* -- Structure of a ZIP file -- */
  638. X
  639. X/* Signatures for zip file information headers */
  640. X#define LOCSIG  0x04034b50L
  641. X#define CENSIG  0x02014b50L
  642. X#define ENDSIG  0x06054b50L
  643. X
  644. X/* Offsets of values in headers */
  645. X#define LOCVER  0               /* version needed to extract */
  646. X#define LOCFLG  2               /* encrypt, implosion flags */
  647. X#define LOCHOW  4               /* compression method */
  648. X#define LOCTIM  6               /* last modified file time, DOS format */
  649. X#define LOCDAT  8               /* last modified file date, DOS format */
  650. X#define LOCCRC  10              /* uncompressed crc-32 for file */
  651. X#define LOCSIZ  14              /* compressed size in zip file */
  652. X#define LOCLEN  18              /* uncompressed size */
  653. X#define LOCNAM  22              /* length of filename */
  654. X#define LOCEXT  24              /* length of extra field */
  655. X
  656. X#define CENVEM  0               /* version made by */
  657. X#define CENVER  2               /* version needed to extract */
  658. X#define CENFLG  4               /* encrypt, implosion flags */
  659. X#define CENHOW  6               /* compression method */
  660. X#define CENTIM  8               /* last modified file time, DOS format */
  661. X#define CENDAT  10              /* last modified file date, DOS format */
  662. X#define CENCRC  12              /* uncompressed crc-32 for file */
  663. X#define CENSIZ  16              /* compressed size in zip file */
  664. X#define CENLEN  20              /* uncompressed size */
  665. X#define CENNAM  24              /* length of filename */
  666. X#define CENEXT  26              /* length of extra field */
  667. X#define CENCOM  28              /* file comment length */
  668. X#define CENDSK  30              /* disk number start */
  669. X#define CENATT  32              /* internal file attributes */
  670. X#define CENATX  34              /* external file attributes */
  671. X#define CENOFF  38              /* relative offset of local header */
  672. X
  673. X#define ENDDSK  0               /* number of this disk */
  674. X#define ENDBEG  2               /* number of the starting disk */
  675. X#define ENDSUB  4               /* entries on this disk */
  676. X#define ENDTOT  6               /* total number of entries */
  677. X#define ENDSIZ  8               /* size of entire central directory */
  678. X#define ENDOFF  12              /* offset of central on starting disk */
  679. X#define ENDCOM  16              /* length of zip file comment */
  680. X
  681. X
  682. X/* Local functions */
  683. X#ifdef PROTO
  684. X   local int zqcmp(voidp *, voidp *);
  685. X#  ifndef UTIL
  686. X     local int zbcmp(voidp *, voidp far *);
  687. X     local char *cutpath(char *);
  688. X#  endif /* !UTIL */
  689. X#endif /* PROTO */
  690. X
  691. X
  692. local int zqcmp(a, b)
  693. voidp *a, *b;           /* pointers to pointers to zip entries */
  694. X/* Used by qsort() to compare entries in the zfile list.  */
  695. X{
  696. X  return strcmp((*(struct zlist far **)a)->zname,
  697. X                (*(struct zlist far **)b)->zname);
  698. X}
  699. X
  700. X
  701. X#ifndef UTIL
  702. X
  703. local int zbcmp(n, z)
  704. voidp *n;               /* string to search for */
  705. voidp far *z;           /* pointer to a pointer to a zip entry */
  706. X/* Used by search() to compare a target to an entry in the zfile list. */
  707. X{
  708. X#ifdef OS2
  709. X  return stricmp((char *)n, ((struct zlist far *)z)->zname);
  710. X#else /* !OS2 */
  711. X  return strcmp((char *)n, ((struct zlist far *)z)->zname);
  712. X#endif /* ?OS2 */
  713. X}
  714. X
  715. X
  716. struct zlist far *zsearch(n)
  717. char *n;                /* name to find */
  718. X/* Return a pointer to the entry in zfile with the name n, or NULL if
  719. X   not found. */
  720. X{
  721. X  voidp far **p;        /* result of search() */
  722. X
  723. X  if (zcount && (p = search(n, (voidp far **)zsort, zcount, zbcmp)) != NULL)
  724. X    return *(struct zlist far **)p;
  725. X  else
  726. X    return NULL;
  727. X}
  728. X
  729. X#endif /* !UTIL */
  730. X
  731. X
  732. X#ifdef VMS
  733. X#  define PATHCUT ']'
  734. X#else /* !VMS */
  735. X#  define PATHCUT '/'
  736. X#endif /* VMS */
  737. X
  738. char *ziptyp(s)
  739. char *s;                /* file name to force to zip */
  740. X/* If the file name *s has a dot (other than the first char), then return
  741. X   the name, otherwise append .zip to the name.  Allocate the space for
  742. X   the name in either case.  Return a pointer to the new name, or NULL
  743. X   if malloc() fails. */
  744. X{
  745. X  char *q;              /* temporary pointer */
  746. X  char *t;              /* pointer to malloc'ed string */
  747. X
  748. X  if ((t = malloc(strlen(s) + 5)) == NULL)
  749. X    return NULL;
  750. X  strcpy(t, s);
  751. X#ifdef MSDOS
  752. X  for (q = t; *q; q++)
  753. X    if (*q == '\\')
  754. X      *q = '/';
  755. X#endif /* MSDOS */
  756. X  if (strrchr((q = strrchr(t, PATHCUT)) == NULL ? t : q + 1, '.') == NULL)
  757. X    strcat(t, ".zip");
  758. X#ifdef MSDOS
  759. X#ifndef OS2
  760. X  strupr(t);
  761. X#endif /* !OS2 */
  762. X#endif /* MSDOS */
  763. X  return t;
  764. X}
  765. X
  766. X
  767. int readzipfile()
  768. X/*
  769. X   Make first pass through zip file, reading information from local file
  770. X   headers and then verifying that information with the central file
  771. X   headers.  Any deviation from the expected zip file format returns an
  772. X   error.  At the end, a sorted list of file names in the zip file is made
  773. X   to facilitate searching by name.
  774. X
  775. X   The name of the zip file is pointed to by the global "zipfile".  The
  776. X   globals zfiles, zcount, zcomlen, zcomment, and zsort are filled in.
  777. X   Return an error code in the ZE_ class.
  778. X*/
  779. X{
  780. X  char b[CENHEAD];      /* buffer for central headers */
  781. X  FILE *f;              /* zip file */
  782. X  int m;                /* mismatch flag */
  783. X  extent n;             /* length of name */
  784. X  ulg p;                /* current file offset */
  785. X  char r;               /* holds reserved bits during memcmp() */
  786. X  ulg s;                /* size of data, start of central */
  787. X  char *t;              /* temporary variable */
  788. X  char far *u;          /* temporary variable */
  789. X  struct zlist far * far *x;    /* pointer last entry's link */
  790. X  struct zlist far *z;  /* current zip entry structure */
  791. X
  792. X  /* Initialize zip file info */
  793. X  zipbeg = 0;
  794. X  zfiles = NULL;                        /* Points to first header */
  795. X  zcomlen = 0;                          /* zip file comment length */
  796. X
  797. X  /* If zip file exists, read headers and check structure */
  798. X  if ((f = fopen(zipfile, FOPR)) != NULL)
  799. X  {
  800. X    x = &zfiles;                        /* first link */
  801. X    p = 0;                              /* starting file offset */
  802. X    zcount = 0;                         /* number of files */
  803. X
  804. X    /* Find start of zip structures */
  805. X    while (fread(b, 4, 1, f) == 1 && (s = LG(b)) != LOCSIG && s != ENDSIG)
  806. X      if (fseek(f, -3L, SEEK_CUR))
  807. X        return ferror(f) ? ZE_READ : ZE_EOF;
  808. X      else
  809. X        p++;
  810. X    zipbeg = p;
  811. X
  812. X    /* Read local headers */
  813. X    while (LG(b) == LOCSIG)
  814. X    {
  815. X      /* Read local header raw to compare later with central header 
  816. X         (this requires that the offest of ext in the zlist structure
  817. X         be greater than or equal to LOCHEAD) */
  818. X      if ((z = (struct zlist far *)farmalloc(sizeof(struct zlist))) == NULL)
  819. X        return ZE_MEM;
  820. X      if (fread(b, LOCHEAD, 1, f) != 1)
  821. X        return ferror(f) ? ZE_READ : ZE_EOF;
  822. X      t = b;  u = (char far *)z;  n = LOCHEAD;
  823. X      do {
  824. X        *u++ = *t++;
  825. X      } while (--n);
  826. X
  827. X      /* Link into list */
  828. X      *x = z;
  829. X      z->nxt = NULL;
  830. X      x = &z->nxt;
  831. X
  832. X      /* Read file name and extra field and skip data */
  833. X      n = SH(LOCNAM + (uch far *)z);
  834. X      z->ext = SH(LOCEXT + (uch far *)z);
  835. X      s = LG(LOCSIZ + (uch far *)z);
  836. X      if (n == 0)
  837. X      {
  838. X        sprintf(errbuf, "%d", zcount + 1);
  839. X        warn("zero-length name for entry #", errbuf);
  840. X        return ZE_FORM;
  841. X      }
  842. X      if ((z->zname = malloc(n+1)) ==  NULL ||
  843. X          (z->ext && (z->extra = malloc(z->ext)) == NULL))
  844. X        return ZE_MEM;
  845. X      if (fread(z->zname, n, 1, f) != 1 ||
  846. X          (z->ext && fread(z->extra, z->ext, 1, f) != 1) ||
  847. X          fseek(f, (long)s, SEEK_CUR))
  848. X        return ferror(f) ? ZE_READ : ZE_EOF;
  849. X      z->zname[n] = 0;                  /* terminate name */
  850. X#ifdef UTIL
  851. X      z->name = z->zname;
  852. X#else /* !UTIL */
  853. X      z->name = in2ex(z->zname);        /* convert to external name */
  854. X      if (z->name == NULL)
  855. X        return ZE_MEM;
  856. X#endif /* ?UTIL */
  857. X
  858. X      /* Save offset, update for next header */
  859. X      z->off = p;
  860. X      p += 4 + LOCHEAD + n + z->ext + s;
  861. X      zcount++;
  862. X
  863. X      /* Read next signature */
  864. X      if (fread(b, 4, 1, f) != 1)
  865. X        return ferror(f) ? ZE_READ : ZE_EOF;
  866. X    }
  867. X
  868. X    /* Point to start of header list and read central headers */
  869. X    z = zfiles;
  870. X    s = p;                              /* save start of central */
  871. X    while (LG(b) == CENSIG)
  872. X    {
  873. X      if (z == NULL)
  874. X      {
  875. X        warn("extraneous central header signature", "");
  876. X        return ZE_FORM;
  877. X      }
  878. X
  879. X      /* Read central header */
  880. X      if (fread(b, CENHEAD, 1, f) != 1)
  881. X        return ferror(f) ? ZE_READ : ZE_EOF;
  882. X
  883. X      /* Compare local header with that part of central header (except
  884. X         for the reserved bits in the general purpose flags and except
  885. X         for length of extra fields--authentication can make these
  886. X         different in central and local headers) */
  887. X      z->lflg = SH(LOCFLG + (uch far *)z);      /* Save reserved bits */
  888. X      r = b[CENFLG+1];
  889. X      ((uch far *)z)[LOCFLG+1] &= 0x1f; /* Zero out reserved bits */
  890. X      b[CENFLG+1] &= 0x1f;
  891. X      for (m = 0, u = (char far *)z, n = 0; n < LOCHEAD - 2; n++)
  892. X        if (u[n] != b[n+2])
  893. X        {
  894. X          if (!m)
  895. X            warn("local and central headers differ for ", z->zname);
  896. X          m = 1;
  897. X          sprintf(errbuf, " offset %d--local = %02x, central = %02x",
  898. X                  n, (uch)u[n], (uch)b[n+2]);
  899. X          warn(errbuf, "");
  900. X        }
  901. X      if (m)
  902. X        return ZE_FORM;
  903. X      b[CENFLG+1] = r;                  /* Restore reserved bits */
  904. X
  905. X      /* Overwrite local header with translated central header */
  906. X      z->vem = SH(CENVEM + b);
  907. X      z->ver = SH(CENVER + b);
  908. X      z->flg = SH(CENFLG + b);          /* may be different from z->lflg */
  909. X      z->how = SH(CENHOW + b);
  910. X      z->tim = LG(CENTIM + b);          /* time and date into one long */
  911. X      z->crc = LG(CENCRC + b);
  912. X      z->siz = LG(CENSIZ + b);
  913. X      z->len = LG(CENLEN + b);
  914. X      z->nam = SH(CENNAM + b);
  915. X      z->cext = SH(CENEXT + b);         /* may be different from z->ext */
  916. X      z->com = SH(CENCOM + b);
  917. X      z->dsk = SH(CENDSK + b);
  918. X      z->att = SH(CENATT + b);
  919. X      z->atx = LG(CENATX + b);
  920. X      if (z->off != LG(CENOFF + b))
  921. X      {
  922. X        warn("local offset in central header incorrect for ", z->zname);
  923. X        return ZE_FORM;
  924. X      }
  925. X
  926. X      /* Compare name and extra fields and read comment field */
  927. X      if ((t = malloc(z->nam)) == NULL)
  928. X        return ZE_MEM;
  929. X      if (fread(t, z->nam, 1, f) != 1)
  930. X      {
  931. X        free((voidp *)t);
  932. X        return ferror(f) ? ZE_READ : ZE_EOF;
  933. X      }
  934. X      if (memcmp(t, z->zname, z->nam))
  935. X      {
  936. X        free((voidp *)t);
  937. X        warn("names in local and central differ for ", z->zname);
  938. X        return ZE_FORM;
  939. X      }
  940. X      free((voidp *)t);
  941. X      if (z->cext)
  942. X      {
  943. X        if ((z->cextra = malloc(z->cext)) == NULL)
  944. X          return ZE_MEM;
  945. X        if (fread(z->cextra, z->cext, 1, f) != 1)
  946. X        {
  947. X          free((voidp *)(z->cextra));
  948. X          return ferror(f) ? ZE_READ : ZE_EOF;
  949. X        }
  950. X        if (z->ext == z->cext && memcmp(z->extra, z->cextra, z->ext) == 0)
  951. X        {
  952. X          free((voidp *)(z->cextra));
  953. X          z->cextra = z->extra;
  954. X        }
  955. X      }
  956. X      if (z->com)
  957. X      {
  958. X        if ((z->comment = malloc(z->com)) == NULL)
  959. X          return ZE_MEM;
  960. X        if (fread(z->comment, z->com, 1, f) != 1)
  961. X        {
  962. X          free((voidp *)(z->comment));
  963. X          return ferror(f) ? ZE_READ : ZE_EOF;
  964. X        }
  965. X      }
  966. X
  967. X      /* Note oddities */
  968. X      if (verbose)
  969. X      {
  970. X        if (z->vem != 10 && z->vem != 11 &&
  971. X            (n = z->vem >> 8) != 3 && n != 2 && n != 6)
  972. X        {
  973. X          sprintf(errbuf, "made by version %d.%d on system type %d: ",
  974. X                  (z->vem & 0xff) / 10, (z->vem & 0xff) % 10, z->vem >> 8);
  975. X          warn(errbuf, z->zname);
  976. X        }
  977. X        if (z->ver != 10 && z->ver != 11)
  978. X        {
  979. X          sprintf(errbuf, "needs unzip %d.%d on system type %d: ",
  980. X                  (z->ver & 0xff) / 10, (z->ver & 0xff) % 10, z->ver >> 8);
  981. X          warn(errbuf, z->zname);
  982. X        }
  983. X        if (z->flg != z->lflg)
  984. X        {
  985. X          sprintf(errbuf, "local flags = 0x%04x, central = 0x%04x: ",
  986. X                  z->lflg, z->flg);
  987. X          warn(errbuf, z->zname);
  988. X        }
  989. X        else if (z->flg & ~7)
  990. X        {
  991. X          sprintf(errbuf, "undefined bits used in flags = 0x%04x: ", z->flg);
  992. X          warn(errbuf, z->zname);
  993. X        }
  994. X        if (z->how > IMPLODE)
  995. X        {
  996. X          sprintf(errbuf, "unknown compression method %u: ", z->how);
  997. X          warn(errbuf, z->zname);
  998. X        }
  999. X        if (z->dsk)
  1000. X        {
  1001. X          sprintf(errbuf, "starts on disk %u: ", z->dsk);
  1002. X          warn(errbuf, z->zname);
  1003. X        }
  1004. X        if (z->att & ~1)
  1005. X        {
  1006. X          sprintf(errbuf, "unknown internal attributes = 0x%04x: ", z->att);
  1007. X          warn(errbuf, z->zname);
  1008. X        }
  1009. X        if (((n = z->vem >> 8) != 3) && n != 2 && z->atx & ~0xffL)
  1010. X        {
  1011. X          sprintf(errbuf, "unknown external attributes = 0x%08lx: ", z->atx);
  1012. X          warn(errbuf, z->zname);
  1013. X        }
  1014. X        if (z->ext || z->cext)
  1015. X          if (z->ext == z->cext && z->extra == z->cextra)
  1016. X          {
  1017. X            sprintf(errbuf, "has %d bytes of extra data: ", z->ext);
  1018. X            warn(errbuf, z->zname);
  1019. X          }
  1020. X          else
  1021. X          {
  1022. X            sprintf(errbuf,
  1023. X                    "local extra (%d bytes) != central extra (%d bytes): ",
  1024. X                    z->ext, z->cext);
  1025. X            warn(errbuf, z->zname);
  1026. X          }
  1027. X      }
  1028. X
  1029. X      /* Clear actions */
  1030. X      z->mark = 0;
  1031. X      z->trash = 0;
  1032. X
  1033. X      /* Update file offset */
  1034. X      p += 4 + CENHEAD + z->nam + z->cext + z->com;
  1035. X
  1036. X      /* Advance to next header structure */
  1037. X      z = z->nxt;
  1038. X
  1039. X      /* Read next signature */
  1040. X      if (fread(b, 4, 1, f) != 1)
  1041. X        return ferror(f) ? ZE_READ : ZE_EOF;
  1042. X    }
  1043. X    
  1044. X    /* Read end header */
  1045. X    if (z != NULL || LG(b) != ENDSIG)
  1046. X    {
  1047. X      warn("missing end signature--probably not a zip file (did you", "");
  1048. X      warn("remember to use binary mode when you transferred it?)", "");
  1049. X      return ZE_FORM;
  1050. X    }
  1051. X    if (fread(b, ENDHEAD, 1, f) != 1)
  1052. X      return ferror(f) ? ZE_READ : ZE_EOF;
  1053. X    if (SH(ENDDSK + b) || SH(ENDBEG + b) ||
  1054. X        SH(ENDSUB + b) != SH(ENDTOT + b))
  1055. X      warn("multiple disk information ignored", "");
  1056. X    if (zcount != SH(ENDSUB + b))
  1057. X    {
  1058. X      warn("count in end of central directory incorrect", "");
  1059. X      return ZE_FORM;
  1060. X    }
  1061. X    if (LG(ENDSIZ + b) != p - s)
  1062. X    {
  1063. X      warn("central directory size is incorrect", "");
  1064. X      return ZE_FORM;
  1065. X    }
  1066. X    if (LG(ENDOFF + b) != s)
  1067. X    {
  1068. X      warn("central directory start is incorrect", "");
  1069. X      return ZE_FORM;
  1070. X    }
  1071. X    cenbeg = s;
  1072. X    zcomlen = SH(ENDCOM + b);
  1073. X    if (zcomlen)
  1074. X    {
  1075. X      if ((zcomment = malloc(zcomlen)) == NULL)
  1076. X        return ZE_MEM;
  1077. X      if (fread(zcomment, zcomlen, 1, f) != 1)
  1078. X      {
  1079. X        free((voidp *)zcomment);
  1080. X        return ferror(f) ? ZE_READ : ZE_EOF;
  1081. X      }
  1082. X    }
  1083. X    if (zipbeg)
  1084. X    {
  1085. X      sprintf(errbuf, " has a preamble of %ld bytes", zipbeg);
  1086. X      warn(zipfile, errbuf);
  1087. X    }
  1088. X    if (getc(f) != EOF)
  1089. X      warn("garbage at end of zip file ignored", "");
  1090. X
  1091. X    /* Done with zip file for now */
  1092. X    fclose(f);
  1093. X    
  1094. X    /* If one or more files, sort by name */
  1095. X    if (zcount)
  1096. X    {
  1097. X      if ((x = zsort =
  1098. X          (struct zlist far **)malloc(zcount * sizeof(struct zlist far *))) ==
  1099. X          NULL)
  1100. X        return ZE_MEM;
  1101. X      for (z = zfiles; z != NULL; z = z->nxt)
  1102. X        *x++ = z;
  1103. X      qsort((char *)zsort, zcount, sizeof(struct zlist far *), zqcmp);
  1104. X    }
  1105. X  }
  1106. X  return ZE_OK;
  1107. X}
  1108. X
  1109. X
  1110. int putlocal(z, f)
  1111. struct zlist far *z;    /* zip entry to write local header for */
  1112. XFILE *f;                /* file to write to */
  1113. X/* Write a local header described by *z to file *f.  Return an error code
  1114. X   in the ZE_ class. */
  1115. X{
  1116. X  PUTLG(LOCSIG, f);
  1117. X  PUTSH(z->ver, f);
  1118. X  PUTSH(z->lflg, f);
  1119. X  PUTSH(z->how, f);
  1120. X  PUTLG(z->tim, f);
  1121. X  PUTLG(z->crc, f);
  1122. X  PUTLG(z->siz, f);
  1123. X  PUTLG(z->len, f);
  1124. X  PUTSH(z->nam, f);
  1125. X  PUTSH(z->ext, f);
  1126. X  if (fwrite(z->zname, 1, z->nam, f) != z->nam ||
  1127. X      z->ext && fwrite(z->extra, 1, z->ext, f) != z->ext)
  1128. X    return ZE_TEMP;
  1129. X  return ZE_OK;
  1130. X}
  1131. X
  1132. X
  1133. int putcentral(z, f)
  1134. struct zlist far *z;    /* zip entry to write central header for */
  1135. XFILE *f;                /* file to write to */
  1136. X/* Write a central header described by *z to file *f.  Return an error code
  1137. X   in the ZE_ class. */
  1138. X{
  1139. X  PUTLG(CENSIG, f);
  1140. X  PUTSH(z->vem, f);
  1141. X  PUTSH(z->ver, f);
  1142. X  PUTSH(z->flg, f);
  1143. X  PUTSH(z->how, f);
  1144. X  PUTLG(z->tim, f);
  1145. X  PUTLG(z->crc, f);
  1146. X  PUTLG(z->siz, f);
  1147. X  PUTLG(z->len, f);
  1148. X  PUTSH(z->nam, f);
  1149. X  PUTSH(z->cext, f);
  1150. X  PUTSH(z->com, f);
  1151. X  PUTSH(z->dsk, f);
  1152. X  PUTSH(z->att, f);
  1153. X  PUTLG(z->atx, f);
  1154. X  PUTLG(z->off, f);
  1155. X  if (fwrite(z->zname, 1, z->nam, f) != z->nam ||
  1156. X      z->cext && fwrite(z->cextra, 1, z->cext, f) != z->cext ||
  1157. X      z->com && fwrite(z->comment, 1, z->com, f) != z->com)
  1158. X    return ZE_TEMP;
  1159. X  return ZE_OK;
  1160. X}
  1161. X
  1162. X
  1163. int putend(n, s, c, m, z, f)
  1164. int n;                  /* number of entries in central directory */
  1165. ulg s, c;               /* size and offset of central directory */
  1166. extent m;               /* length of zip file comment (0 if none) */
  1167. char *z;                /* zip file comment if m != 0 */
  1168. XFILE *f;                /* file to write to */
  1169. X/* Write the end of central directory data to file *f.  Return an error code
  1170. X   in the ZE_ class. */
  1171. X{
  1172. X  PUTLG(ENDSIG, f);
  1173. X  PUTSH(0, f);
  1174. X  PUTSH(0, f);
  1175. X  PUTSH(n, f);
  1176. X  PUTSH(n, f);
  1177. X  PUTLG(s, f);
  1178. X  PUTLG(c, f);
  1179. X  PUTSH(m, f);
  1180. X  if (m && fwrite(z, 1, m, f) != m)
  1181. X    return ZE_TEMP;
  1182. X  return ZE_OK;
  1183. X}
  1184. X
  1185. X
  1186. X#ifndef UTIL
  1187. X
  1188. local char *cutpath(p)
  1189. char *p;                /* path string */
  1190. X/* Cut the last path component off the name *p in place.  Return p. */
  1191. X{
  1192. X  char *r;              /* pointer to last path delimiter */
  1193. X
  1194. X#ifdef VMS                      /* change [w.x.y]z to [w.x]y.DIR */
  1195. X  if ((r = strrchr(p, ']')) != NULL)
  1196. X  {
  1197. X    *r = 0;
  1198. X    if ((r = strrchr(p, '.')) != NULL)
  1199. X    {
  1200. X      *r = ']';
  1201. X      strcat(r, ".DIR");        /* this assumes a little padding--see PAD */
  1202. X    }
  1203. X    else
  1204. X      *p = 0;
  1205. X  }
  1206. X  else
  1207. X    *p = 0;
  1208. X#else /* !VMS */                /* change w/x/y/z to w/x/y */
  1209. X  if ((r = strrchr(p, '/')) != NULL)
  1210. X    *r = 0;
  1211. X  else
  1212. X    *p = 0;
  1213. X#endif /* ?VMS */
  1214. X  return p;
  1215. X}
  1216. X
  1217. X
  1218. int trash()
  1219. X/* Delete the compressed files and the directories that contained the deleted
  1220. X   files, if empty.  Return an error code in the ZE_ class.  Failure of
  1221. X   destroy() or deletedir() is ignored. */
  1222. X{
  1223. X  extent i;             /* counter on deleted names */
  1224. X  extent k;             /* number of deleted directories this pass */
  1225. X  extent n;             /* number of deleted names left to handle */
  1226. X  struct zlist far **s; /* table of zip entries to handle, sorted */
  1227. X  struct zlist far *z;  /* current zip entry */
  1228. X
  1229. X  /* Count and delete marked names */
  1230. X  n = 0;
  1231. X  for (z = zfiles; z != NULL; z = z->nxt)
  1232. X    if (z->mark || z->trash)
  1233. X    {
  1234. X      z->mark = 1;
  1235. X      n++;
  1236. X      if (verbose)
  1237. X        printf("zip diagnostic: trashing file %s\n", z->name);
  1238. X      destroy(z->name);
  1239. X    }
  1240. X
  1241. X  /* Try to delete all paths that lead up to marked names */
  1242. X  if (n)
  1243. X  {
  1244. X    if ((s = (struct zlist far **)malloc((n+1)*sizeof(struct zlist far *))) ==
  1245. X        NULL ||
  1246. X        (s[0] = (struct zlist far *)farmalloc(sizeof(struct zlist))) == NULL)
  1247. X      return ZE_MEM;
  1248. X    s[0]->name = "";
  1249. X    s++;
  1250. X    do {
  1251. X      n = k = 0;
  1252. X      for (z = zfiles; z != NULL; z = z->nxt)
  1253. X        if (z->mark)
  1254. X          s[n++] = z;
  1255. X      qsort((char *)s, n, sizeof(struct zlist far *), zqcmp);
  1256. X      for (i = 0; i < n; i++)
  1257. X        if (*cutpath(s[i]->name) && strcmp(s[i]->name, s[i-1]->name))
  1258. X        {
  1259. X          if (verbose)
  1260. X            printf("zip diagnostic: trashing directory %s\n", s[i]->name);
  1261. X          deletedir(s[i]->name);
  1262. X          k++;
  1263. X        }
  1264. X        else
  1265. X          s[i]->mark = 0;
  1266. X    } while (k);
  1267. X    farfree((voidp far *)((--s)[0]));
  1268. X    free((voidp *)s);
  1269. X  }
  1270. X  return ZE_OK;
  1271. X}
  1272. X
  1273. X#endif /* !UTIL */
  1274. END_OF_FILE
  1275. if test 20530 -ne `wc -c <'zipfile.c'`; then
  1276.     echo shar: \"'zipfile.c'\" unpacked with wrong size!
  1277. fi
  1278. # end of 'zipfile.c'
  1279. fi
  1280. if test -f 'zipsplit.c' -a "${1}" != "-c" ; then 
  1281.   echo shar: Will not clobber existing file \"'zipsplit.c'\"
  1282. else
  1283. echo shar: Extracting \"'zipsplit.c'\" \(16863 characters\)
  1284. sed "s/^X//" >'zipsplit.c' <<'END_OF_FILE'
  1285. X/*
  1286. X
  1287. X Copyright (C) 1990,1991 Mark Adler, Richard B. Wales, and Jean-loup Gailly.
  1288. X Permission is granted to any individual or institution to use, copy, or
  1289. X redistribute this software so long as all of the original files are included
  1290. X unmodified, that it is not sold for profit, and that this copyright notice
  1291. X is retained.
  1292. X
  1293. X*/
  1294. X
  1295. X/*
  1296. X *  zipsplit.c by Mark Adler.
  1297. X */
  1298. X
  1299. X#define UTIL
  1300. X#include "revision.h"
  1301. X#include "zip.h"
  1302. X#include <signal.h>
  1303. X
  1304. X#define DEFSIZ 36000L   /* Default split size (change in help() too) */
  1305. X#ifdef MSDOS
  1306. X#  define NL 2          /* Number of bytes written for a \n */
  1307. X#else /* !MSDOS */
  1308. X#  define NL 1          /* Number of bytes written for a \n */
  1309. X#endif /* ?MSDOS */
  1310. X#define INDEX "zipsplit.idx"    /* Name of index file */
  1311. X
  1312. X
  1313. X/* Local functions */
  1314. X#ifdef PROTO
  1315. X   local void err(int, char *);
  1316. X   local void handler(int);
  1317. X   local void license(void);
  1318. X   local void help(void);
  1319. X   local extent simple(ulg *, extent, ulg, ulg);
  1320. X   local int descmp(voidp *, voidp *);
  1321. X   local extent greedy(ulg *, extent, ulg, ulg);
  1322. X   void main(int, char **);
  1323. X#endif /* PROTO */
  1324. X
  1325. X
  1326. X/* Output zip files */
  1327. local char template[16];        /* name template for output files */
  1328. local int zipsmade = 0;         /* number of zip files made */
  1329. local int indexmade = 0;        /* true if index file made */
  1330. local char *path = NULL;        /* space for full name */
  1331. local char *name;               /* where name goes in path[] */
  1332. X
  1333. X
  1334. local void err(c, h)
  1335. int c;                  /* error code from the ZE_ class */
  1336. char *h;                /* message about how it happened */
  1337. X/* Issue a message for the error, clean up files and memory, and exit. */
  1338. X{
  1339. X  if (PERR(c))
  1340. X    perror("zipsplit error");
  1341. X  fprintf(stderr, "zipsplit error: %s (%s)\n", errors[c-1], h);
  1342. X  if (indexmade)
  1343. X  {
  1344. X    strcpy(name, INDEX);
  1345. X    destroy(path);
  1346. X  }
  1347. X  for (; zipsmade; zipsmade--)
  1348. X  {
  1349. X    sprintf(name, template, zipsmade);
  1350. X    destroy(path);
  1351. X  }
  1352. X  if (path != NULL)
  1353. X    free((voidp *)path);
  1354. X  if (zipfile != NULL)
  1355. X    free((voidp *)zipfile);
  1356. X#ifdef VMS
  1357. X  exit(0);
  1358. X#else /* !VMS */
  1359. X  exit(c);
  1360. X#endif /* ?VMS */
  1361. X}
  1362. X
  1363. X
  1364. X
  1365. local void handler(s)
  1366. int s;                  /* signal number (ignored) */
  1367. X/* Upon getting a user interrupt, abort cleanly using err(). */
  1368. X{
  1369. X#ifndef MSDOS
  1370. X  putc('\n', stderr);
  1371. X#endif /* !MSDOS */
  1372. X  err(ZE_ABORT, "aborting");
  1373. X  s++;                                  /* keep some compilers happy */
  1374. X}
  1375. X
  1376. X
  1377. void warn(a, b)
  1378. char *a, *b;            /* message strings juxtaposed in output */
  1379. X/* Print a warning message to stderr and return. */
  1380. X{
  1381. X  fprintf(stderr, "zipsplit warning: %s%s\n", a, b);
  1382. X}
  1383. X
  1384. X
  1385. local void license()
  1386. X/* Print license information to stdout. */
  1387. X{
  1388. X  extent i;             /* counter for copyright array */
  1389. X
  1390. X  for (i = 0; i < sizeof(copyright)/sizeof(char *); i++)
  1391. X    puts(copyright[i]);
  1392. X  for (i = 0; i < sizeof(disclaimer)/sizeof(char *); i++)
  1393. X    puts(disclaimer[i]);
  1394. X}
  1395. X
  1396. X
  1397. local void help()
  1398. X/* Print help (along with license info) to stdout. */
  1399. X{
  1400. X  extent i;             /* counter for help array */
  1401. X
  1402. X  /* help array */
  1403. X  static char *text[] = {
  1404. X"",
  1405. X"ZipSplit %d.%d (%s)",
  1406. X"Usage:  zipsplit [-ti] [-n size] [-b path] zipfile",
  1407. X"  -t   report how many files it will take, but don't make them",
  1408. X"  -i   make index (zipsplit.idx) and count its size against first zip file",
  1409. X"  -n   make zip files no larger than \"size\" (default = 36000)",
  1410. X"  -b   use \"path\" for the output zip files",
  1411. X"  -s   do a sequential split even if it takes more zip files",
  1412. X"  -h   show this help               -l   show software license"
  1413. X  };
  1414. X
  1415. X  for (i = 0; i < sizeof(copyright)/sizeof(char *); i++)
  1416. X    puts(copyright[i]);
  1417. X  for (i = 0; i < sizeof(text)/sizeof(char *); i++)
  1418. X  {
  1419. X    printf(text[i], REVISION / 10, REVISION % 10, REVDATE);
  1420. X    putchar('\n');
  1421. X  }
  1422. X}
  1423. X
  1424. X
  1425. local extent simple(a, n, c, d)
  1426. ulg *a;         /* items to put in bins, return value: destination bins */
  1427. extent n;       /* number of items */
  1428. ulg c;          /* capacity of each bin */
  1429. ulg d;          /* amount to deduct from first bin */
  1430. X/* Return the number of bins of capacity c that are needed to contain the
  1431. X   integers in a[0..n-1] placed sequentially into the bins.  The value d
  1432. X   is deducted initially from the first bin (space for index).  The entries
  1433. X   in a[] are replaced by the destination bins. */
  1434. X{
  1435. X  extent k;     /* current bin number */
  1436. X  ulg t;        /* space used in current bin */
  1437. X
  1438. X  t = k = 0;
  1439. X  while (n--)
  1440. X  {
  1441. X    if (*a + t > c - (k == 0 ? d : 0))
  1442. X    {
  1443. X      k++;
  1444. X      t = 0;
  1445. X    }
  1446. X    t += *a;
  1447. X    *(ulg huge *)a++ = k;
  1448. X  }
  1449. X  return k + 1;
  1450. X}
  1451. X
  1452. X
  1453. local int descmp(a, b)
  1454. voidp *a, *b;           /* pointers to pointers to ulg's to compare */
  1455. X/* Used by qsort() in greedy() to do a descending sort. */
  1456. X{
  1457. X  return **(ulg **)a < **(ulg **)b ? 1 : (**(ulg **)a > **(ulg **)b ? -1 : 0);
  1458. X}
  1459. X
  1460. X
  1461. local extent greedy(a, n, c, d)
  1462. ulg *a;         /* items to put in bins, return value: destination bins */
  1463. extent n;       /* number of items */
  1464. ulg c;          /* capacity of each bin */
  1465. ulg d;          /* amount to deduct from first bin */
  1466. X/* Return the number of bins of capacity c that are needed to contain the
  1467. X   items with sizes a[0..n-1] placed non-sequentially into the bins.  The
  1468. X   value d is deducted initially from the first bin (space for index).
  1469. X   The entries in a[] are replaced by the destination bins. */
  1470. X{
  1471. X  ulg *b;       /* space left in each bin (malloc'ed for each m) */
  1472. X  ulg *e;       /* copy of argument a[] (malloc'ed) */
  1473. X  extent i;     /* steps through items */
  1474. X  extent j;     /* steps through bins */
  1475. X  extent k;     /* best bin to put current item in */
  1476. X  extent m;     /* current number of bins */
  1477. X  ulg **s;      /* pointers to e[], sorted descending (malloc'ed) */
  1478. X  ulg t;        /* space left in best bin (index k) */
  1479. X
  1480. X  /* Algorithm:
  1481. X     1. Copy a[] to e[] and sort pointers to e[0..n-1] (in s[]), in
  1482. X        descending order.
  1483. X     2. Compute total of s[] and set m to the smallest number of bins of
  1484. X        capacity c that can hold the total.
  1485. X     3. Allocate m bins.
  1486. X     4. For each item in s[], starting with the largest, put it in the
  1487. X        bin with the smallest current capacity greater than or equal to the
  1488. X        item's size.  If no bin has enough room, increment m and go to step 4.
  1489. X     5. Else, all items ended up in a bin--return m.
  1490. X  */
  1491. X
  1492. X  /* Copy a[] to e[], put pointers to e[] in s[], and sort s[].  Also compute
  1493. X     the initial number of bins (minus 1). */
  1494. X  if ((e = (ulg *)malloc(n * sizeof(ulg))) == NULL ||
  1495. X      (s = (ulg **)malloc(n * sizeof(ulg *))) == NULL)
  1496. X  {
  1497. X    if (e != NULL)
  1498. X      free((voidp *)e);
  1499. X    err(ZE_MEM, "was trying a smart split");
  1500. X    return 0;                           /* only to make compiler happy */
  1501. X  }
  1502. X  memcpy((char *)e, (char *)a, n * sizeof(ulg));
  1503. X  for (t = i = 0; i < n; i++)
  1504. X    t += *(s[i] = e + i);
  1505. X  m = (extent)((t + c - 1) / c) - 1;    /* pre-decrement for loop */
  1506. X  qsort((char *)s, n, sizeof(ulg *), descmp);
  1507. X
  1508. X  /* Stuff bins until successful */
  1509. X  do {
  1510. X    /* Increment the number of bins, allocate and initialize bins */
  1511. X    if ((b = (ulg *)malloc(++m * sizeof(ulg))) == NULL)
  1512. X    {
  1513. X      free((voidp *)s);
  1514. X      free((voidp *)e);
  1515. X      err(ZE_MEM, "was trying a smart split");
  1516. X    }
  1517. X    b[0] = c - d;                       /* leave space in first bin */
  1518. X    for (j = 1; j < m; j++)
  1519. X      b[j] = c;
  1520. X
  1521. X    /* Fill the bins greedily */
  1522. X    for (i = 0; i < n; i++)
  1523. X    {
  1524. X      /* Find smallest bin that will hold item i (size s[i]) */
  1525. X      t = c + 1;
  1526. X      for (k = j = 0; j < m; j++)
  1527. X        if (*s[i] <= b[j] && b[j] < t)
  1528. X          t = b[k = j];
  1529. X
  1530. X      /* If no bins big enough for *s[i], try next m */
  1531. X      if (t == c + 1)
  1532. X        break;
  1533. X
  1534. X      /* Diminish that bin and save where it goes */
  1535. X      b[k] -= *s[i];
  1536. X      a[(int)((ulg huge *)(s[i]) - (ulg huge *)e)] = k;
  1537. X    }
  1538. X
  1539. X    /* Clean up */
  1540. X    free((voidp *)b);
  1541. X
  1542. X    /* Do until all items put in a bin */
  1543. X  } while (i < n);
  1544. X
  1545. X  /* Done--clean up and return the number of bins needed */
  1546. X  free((voidp *)s);
  1547. X  free((voidp *)e);
  1548. X  return m;
  1549. X}
  1550. X
  1551. X
  1552. void main(argc, argv)
  1553. int argc;               /* number of tokens in command line */
  1554. char **argv;            /* command line tokens */
  1555. X/* Split a zip file into several zip files less than a specified size.  See
  1556. X   the command help in help() above. */
  1557. X{
  1558. X  ulg *a;               /* malloc'ed list of sizes, dest bins */
  1559. X  extent *b;            /* heads of bin linked lists (malloc'ed) */
  1560. X  ulg c;                /* bin capacity, start of central directory */
  1561. X  int d;                /* if true, just report the number of disks */
  1562. X  FILE *e;              /* input zip file */
  1563. X  FILE *f;              /* output index and zip files */
  1564. X  extent g;             /* number of bins from greedy(), entry to write */
  1565. X  int h;                /* how to split--true means simple split, counter */
  1566. X  ulg i;                /* size of index file or zero if none */
  1567. X  extent j;             /* steps through zip entries, bins */
  1568. X  int k;                /* next argument type */
  1569. X  ulg *p;               /* malloc'ed list of sizes, dest bins for greedy() */
  1570. X  char *q;              /* steps through option characters */
  1571. X  int r;                /* temporary variable, counter */
  1572. X  extent s;             /* number of bins needed */
  1573. X  ulg t;                /* total of sizes, end of central directory */
  1574. X  struct zlist far **w; /* malloc'ed table for zfiles linked list */
  1575. X  int x;                /* if true, make an index file */
  1576. X  struct zlist far *z;  /* steps through zfiles linked list */
  1577. X
  1578. X
  1579. X  /* If no args, show help */
  1580. X  if (argc == 1)
  1581. X  {
  1582. X    help();
  1583. X    exit(0);
  1584. X  }
  1585. X
  1586. X  /* Go through args */
  1587. X  signal(SIGINT, handler);
  1588. X  signal(SIGTERM, handler);
  1589. X  k = h = x = d = 0;
  1590. X  c = DEFSIZ;
  1591. X  for (r = 1; r < argc; r++)
  1592. X    if (*argv[r] == '-')
  1593. X      if (argv[r][1])
  1594. X        for (q = argv[r]+1; *q; q++)
  1595. X          switch(*q)
  1596. X          {
  1597. X            case 'b':   /* Specify path for output files */
  1598. X              if (k)
  1599. X                err(ZE_PARMS, "options are separate and precede zip file");
  1600. X              else
  1601. X                k = 1;          /* Next non-option is path */
  1602. X              break;
  1603. X            case 'h':   /* Show help */
  1604. X              help();  exit(0);
  1605. X            case 'i':   /* Make an index file */
  1606. X              x = 1;
  1607. X              break;
  1608. X            case 'l':   /* Show copyright and disclaimer */
  1609. X              license();  exit(0);
  1610. X            case 'n':   /* Specify maximum size of resulting zip files */
  1611. X              if (k)
  1612. X                err(ZE_PARMS, "options are separate and precede zip file");
  1613. X              else
  1614. X                k = 2;          /* Next non-option is size */
  1615. X              break;
  1616. X            case 's':
  1617. X              h = 1;    /* Only try simple */
  1618. X              break;
  1619. X            case 't':   /* Just report number of disks */
  1620. X              d = 1;
  1621. X              break;
  1622. X            default:
  1623. X              err(ZE_PARMS, "unknown option");
  1624. X          }
  1625. X      else
  1626. X        err(ZE_PARMS, "zip file cannot be stdin");
  1627. X    else
  1628. X      if (k == 0)
  1629. X        if (zipfile == NULL)
  1630. X        {
  1631. X          if ((zipfile = ziptyp(argv[r])) == NULL)
  1632. X            err(ZE_MEM, "was processing arguments");
  1633. X        }
  1634. X        else
  1635. X          err(ZE_PARMS, "can only specify one zip file");
  1636. X      else if (k == 1)
  1637. X      {
  1638. X        tempath = argv[r];
  1639. X        k = 0;
  1640. X      }
  1641. X      else              /* k must be 2 */
  1642. X      {
  1643. X        if ((c = (ulg)atol(argv[r])) < 100)     /* 100 is smallest zip file */
  1644. X          err(ZE_PARMS, "invalid size given");
  1645. X        k = 0;
  1646. X      }
  1647. X  if (zipfile == NULL)
  1648. X    err(ZE_PARMS, "need to specify zip file");
  1649. X
  1650. X
  1651. X  /* Read zip file */
  1652. X  if ((r = readzipfile()) != ZE_OK)
  1653. X    err(r, zipfile);
  1654. X  if (zfiles == NULL)
  1655. X    err(ZE_NAME, zipfile);
  1656. X
  1657. X  /* Make a list of sizes and check against capacity.  Also compute the
  1658. X     size of the index file. */
  1659. X  c -= ENDHEAD + 4;                     /* subtract overhead/zipfile */
  1660. X  if ((a = (ulg *)malloc(zcount * sizeof(ulg))) == NULL ||
  1661. X      (w = (struct zlist far **)malloc(zcount * sizeof(struct zlist far *))) ==
  1662. X       NULL)
  1663. X  {
  1664. X    if (a != NULL)
  1665. X      free((voidp *)a);
  1666. X    err(ZE_MEM, "was computing split");
  1667. X    return;
  1668. X  }
  1669. X  i = t = 0;
  1670. X  for (j = 0, z = zfiles; j < zcount; j++, z = z->nxt)
  1671. X  {
  1672. X    w[j] = z;
  1673. X    if (x)
  1674. X      i += z->nam + 6 + NL;
  1675. X    t += a[j] = 8 + LOCHEAD + CENHEAD +
  1676. X           2 * (ulg)z->nam + 2 * (ulg)z->ext + z->com + z->siz;
  1677. X    if (a[j] > c)
  1678. X    {
  1679. X      free((voidp *)w);  free((voidp *)a);
  1680. X      err(ZE_BIG, z->zname);
  1681. X    }
  1682. X  }
  1683. X
  1684. X  /* Decide on split to use, report number of files */
  1685. X  if (h)
  1686. X    s = simple(a, zcount, c, i);
  1687. X  else
  1688. X  {
  1689. X    if ((p = (ulg *)malloc(zcount * sizeof(ulg))) == NULL)
  1690. X    {
  1691. X      free((voidp *)w);  free((voidp *)a);
  1692. X      err(ZE_MEM, "was computing split");
  1693. X    }
  1694. X    memcpy((char *)p, (char *)a, zcount * sizeof(ulg));
  1695. X    s = simple(a, zcount, c, i);
  1696. X    g = greedy(p, zcount, c, i);
  1697. X    if (s <= g)
  1698. X      free((voidp *)p);
  1699. X    else
  1700. X    {
  1701. X      free((voidp *)a);
  1702. X      a = p;
  1703. X      s = g;
  1704. X    }
  1705. X  }
  1706. X  printf("%d zip files w%s be made (%d%% efficiency)\n",
  1707. X         s, d ? "ould" : "ill", ((200 * ((t + c - 1)/c)) / s + 1) >> 1);
  1708. X  if (d)
  1709. X  {
  1710. X    free((voidp *)w);  free((voidp *)a);
  1711. X    free((voidp *)zipfile);
  1712. X    zipfile = NULL;
  1713. X    return;
  1714. X  }
  1715. X
  1716. X  /* Set up path for output files */
  1717. X  if ((path = malloc(tempath == NULL ? 13 : strlen(tempath) + 14)) == NULL)
  1718. X    err(ZE_MEM, "was making output file names");
  1719. X  if (tempath == NULL)
  1720. X     name = path;
  1721. X  else
  1722. X  {
  1723. X    strcpy(path, tempath);
  1724. X    if (path[0] && path[strlen(path) - 1] != '/')
  1725. X      strcat(path, "/");
  1726. X    name = path + strlen(path);
  1727. X  }
  1728. X
  1729. X  /* Write the index file */
  1730. X  if (x)
  1731. X  {
  1732. X    strcpy(name, INDEX);
  1733. X    printf("creating %s\n", path);
  1734. X    indexmade = 1;
  1735. X    if ((f = fopen(path, "w")) == NULL)
  1736. X    {
  1737. X      free((voidp *)w);  free((voidp *)a);
  1738. X      err(ZE_CREAT, path);
  1739. X    }
  1740. X    for (j = 0; j < zcount; j++)
  1741. X      fprintf(f, "%5ld %s\n", a[j] + 1, w[j]->zname);
  1742. X    if ((j = ferror(f)) != 0 || fclose(f))
  1743. X    {
  1744. X      if (j)
  1745. X        fclose(f);
  1746. X      free((voidp *)w);  free((voidp *)a);
  1747. X      err(ZE_WRITE, path);
  1748. X    }
  1749. X  }
  1750. X
  1751. X  /* Make linked lists of results */
  1752. X  if ((b = (extent *)malloc(s * sizeof(extent))) == NULL)
  1753. X  {
  1754. X    free((voidp *)w);  free((voidp *)a);
  1755. X    err(ZE_MEM, "was computing split");
  1756. X  }
  1757. X  for (j = 0; j < s; j++)
  1758. X    b[j] = -1;
  1759. X  j = zcount;
  1760. X  while (j--)
  1761. X  {
  1762. X    g = (extent)a[j];
  1763. X    a[j] = b[g];
  1764. X    b[g] = j;
  1765. X  }
  1766. X
  1767. X  /* Make a name template for the zip files that is eight or less characters
  1768. X     before the .zip, and that will not overwrite the original zip file. */
  1769. X  for (k = 1, j = s; j >= 10; j /= 10)
  1770. X    k++;
  1771. X  if (k > 7)
  1772. X  {
  1773. X    free((voidp *)b);  free((voidp *)w);  free((voidp *)a);
  1774. X    err(ZE_PARMS, "way too many zip files must be made");
  1775. X  }
  1776. X  if ((q = strrchr(zipfile, '/')) != NULL)
  1777. X    q++;
  1778. X  else
  1779. X    q = zipfile;
  1780. X  r = 0;
  1781. X  while ((g = *q++) != 0 && g != '.' && r < 8 - k)
  1782. X    template[r++] = (char)g;
  1783. X  if (r == 0)
  1784. X    template[r++] = '_';
  1785. X  else if (g >= '0' && g <= '9')
  1786. X    template[r - 1] = (char)(template[r - 1] == '_' ? '-' : '_');
  1787. X  sprintf(template + r, "%%0%dd.zip", k);
  1788. X
  1789. X  /* Make the zip files from the linked lists of entry numbers */
  1790. X  if ((e = fopen(zipfile, FOPR)) == NULL)
  1791. X  {
  1792. X    free((voidp *)b);  free((voidp *)w);  free((voidp *)a);
  1793. X    err(ZE_NAME, zipfile);
  1794. X  }
  1795. X  free((voidp *)zipfile);
  1796. X  zipfile = NULL;
  1797. X  for (j = 0; j < s; j++)
  1798. X  {
  1799. X    sprintf(name, template, j + 1);
  1800. X    printf("creating %s\n", path);
  1801. X    zipsmade = j + 1;
  1802. X    if ((f = fopen(path, FOPW)) == NULL)
  1803. X    {
  1804. X      free((voidp *)b);  free((voidp *)w);  free((voidp *)a);
  1805. X      err(ZE_CREAT, path);
  1806. X    }
  1807. X    for (g = b[j]; g != (extent)-1; g = (extent)a[g])
  1808. X    {
  1809. X      if (fseek(e, w[g]->off, SEEK_SET))
  1810. X      {
  1811. X        free((voidp *)b);  free((voidp *)w);  free((voidp *)a);
  1812. X        err(ferror(e) ? ZE_READ : ZE_EOF, zipfile);
  1813. X      }
  1814. X      if ((r = zipcopy(w[g], e, f)) != ZE_OK)
  1815. X      {
  1816. X        free((voidp *)b);  free((voidp *)w);  free((voidp *)a);
  1817. X        if (r == ZE_TEMP)
  1818. X          err(ZE_WRITE, path);
  1819. X        else
  1820. X          err(r, zipfile);
  1821. X      }
  1822. X    }
  1823. X    if ((c = ftell(f)) == -1L)
  1824. X    {
  1825. X      free((voidp *)b);  free((voidp *)w);  free((voidp *)a);
  1826. X      err(ZE_WRITE, path);
  1827. X    }
  1828. X    for (g = b[j], k = 0; g != (extent)-1; g = (extent)a[g], k++)
  1829. X      if ((r = putcentral(w[g], f)) != ZE_OK)
  1830. X      {
  1831. X        free((voidp *)b);  free((voidp *)w);  free((voidp *)a);
  1832. X        err(ZE_WRITE, path);
  1833. X      }
  1834. X    if ((t = ftell(f)) == -1L)
  1835. X    {
  1836. X      free((voidp *)b);  free((voidp *)w);  free((voidp *)a);
  1837. X      err(ZE_WRITE, path);
  1838. X    }
  1839. X    if ((r = putend(k, t - c, c, (extent)0, (char *)NULL, f)) != ZE_OK)
  1840. X    {
  1841. X      free((voidp *)b);  free((voidp *)w);  free((voidp *)a);
  1842. X      err(ZE_WRITE, path);
  1843. X    }
  1844. X    if (ferror(f) || fclose(f))
  1845. X    {
  1846. X      free((voidp *)b);  free((voidp *)w);  free((voidp *)a);
  1847. X      err(ZE_WRITE, path);
  1848. X    }
  1849. X  }
  1850. X  free((voidp *)b);  free((voidp *)w);  free((voidp *)a);
  1851. X  fclose(e);
  1852. X
  1853. X  /* Done! */
  1854. X  exit(0);
  1855. X}
  1856. END_OF_FILE
  1857. if test 16863 -ne `wc -c <'zipsplit.c'`; then
  1858.     echo shar: \"'zipsplit.c'\" unpacked with wrong size!
  1859. fi
  1860. # end of 'zipsplit.c'
  1861. fi
  1862. echo shar: End of archive 3 \(of 7\).
  1863. cp /dev/null ark3isdone
  1864. MISSING=""
  1865. for I in 1 2 3 4 5 6 7 ; do
  1866.     if test ! -f ark${I}isdone ; then
  1867.     MISSING="${MISSING} ${I}"
  1868.     fi
  1869. done
  1870. if test "${MISSING}" = "" ; then
  1871.     echo You have unpacked all 7 archives.
  1872.     rm -f ark[1-9]isdone
  1873. else
  1874.     echo You still need to unpack the following archives:
  1875.     echo "        " ${MISSING}
  1876. fi
  1877. ##  End of shell archive.
  1878. exit 0
  1879.